﻿namespace OA.Infrastructure.Impl;

public class LogService : ILogService
{
    private readonly DbContext _context;

    public LogService(DbContext context)
    {
        _context = context;
    }

    public async Task<PageResult<Log.QueryModel>> GetPageAsync(Log.ConditionSelectorCondition condition, CancellationToken cancellationToken)
    {
        var result = new PageResult<Log.QueryModel>();

        try
        {
            var expression = GetConditionSelectorCondition(condition);

            var data = await _context.Set<Log>()
                .Include(m => m.Operator).ThenInclude(x => x.DirectLeader)
                .Include(m => m.Operator).ThenInclude(x => x.Department)
                .Include(m => m.Operator).ThenInclude(x => x.Roles)
                .Where(expression)
                .OrderByDescending(n => n.CreatedDate)
                .Skip((condition.PageNum - 1) * condition.PageSize)
                .Take(condition.PageSize)
                .AsNoTracking()
                .ToListAsync(cancellationToken);

            result.Data = data.Select(x => GetQueryModel(x));

            result.PageNum = condition.PageNum;

            result.PageSize = condition.PageSize;

            result.Total = await _context.Set<Log>().CountAsync(expression, cancellationToken);

            result.Status = OperationalResult.SUCCESS;
        }
        catch (Exception error)
        {
            result.Status = OperationalResult.ERROR;

            result.Message = error.ToString();
        }

        return result;
    }

    private static Log.QueryModel GetQueryModel(Log log)
    {
        return new Log.QueryModel
        {
            Id = log.Id,
            CreatedDate = log.CreatedDate,
            LastModifiedDate = log.LastModifiedDate,
            Operator = UserService.GetQueryModel(log.Operator),
            Operation = log.Operation,
            FormId = log.FormId,
            FormType = log.FormType,
            Field = log.Field,
            Old = log.Old,
            New = log.New,
        };
    }

    private static Expression<Func<Log, bool>> GetConditionSelectorCondition(Log.ConditionSelectorCondition condition)
    {
        Expression<Func<Log, bool>>? expression = null;

        if (condition.LogOperation is not null)
        {
            Expression<Func<Log, bool>>? logOperation = null;
            logOperation = log => condition.LogOperation == log.Operation;
            expression = expression?.And(logOperation) ?? logOperation;
        }

        var createDateSelectorCondition = new Log.CreateDateSelectorCondition()
        {
            BeginDate = condition.CreateDateSelectorBeginDate,
            EndDate = condition.CreateDateSelectorEndDate,
        };

        var createDateSelectorExpression = GetCreateDateSelectorCondition(createDateSelectorCondition);

        if (createDateSelectorExpression is not null)
        {
            expression = expression?.And(createDateSelectorExpression) ?? createDateSelectorExpression;
        }

        return expression ?? (log => true);
    }

    private static Expression<Func<Log, bool>>? GetCreateDateSelectorCondition(Log.CreateDateSelectorCondition condition)
    {
        Expression<Func<Log, bool>>? expression = null;

        if (condition.BeginDate is not null)
        {
            Expression<Func<Log, bool>>? beginDate = null;
            beginDate = log => condition.BeginDate <= log.CreatedDate;
            expression = expression?.And(beginDate) ?? beginDate;
        }

        if (condition.EndDate is not null)
        {
            Expression<Func<Log, bool>>? endDate = null;
            endDate = log => condition.EndDate >= log.CreatedDate;
            expression = expression?.And(endDate) ?? endDate;
        }

        return expression;
    }
}